﻿//-----------------------------------------------------------------------
// <copyright>
//     Copyright (c) Artur Mustafin. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Expressions.Compiler
{
    using System;
    using System.Collections.Generic;

    using Interfaces;

    public sealed class Expression<T, V>
    {
        private readonly string _name;

        internal string Name { get { return _name; } }

        private static readonly Dictionary<string, Expression<T, V>> _expressions;

        static Expression()
        {
            _expressions = new Dictionary<string, Expression<T, V>>();
        }

        private Expression(string name)
        {
            _name = name;
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="System.String"/> to <see cref="Expressions.Compiler.Nonterminal"/>.
        /// </summary>
        /// <param name="name">The input name</param>
        /// <returns>The result of the conversion.</returns>
        public static implicit operator Expression<T, V>(string name)
        {
            return GetExpressions(name);
        }

        private static Expression<T, V> GetExpressions(string name)
        {
            if (!_expressions.ContainsKey(name))
            {
                _expressions.Add(name, new Expression<T, V>(name));
            }
            return _expressions[name];
        }

        private Func<V, IExpressionTree<T>, V> _method;

        public Func<V, IExpressionTree<T>, V> Eval
        {
            set
            {
                _method = value;
            }
        }

        public V this[V value, IExpressionTree<T> tree]
        {
            get
            {
                if (tree != null)
                {
                    return _method(value, tree[0]);
                }
                return value;
            }
        }

        public V this[IExpressionTree<T> tree]
        {
            get
            {
                if (tree != null)
                {
                    return _method(default(V), tree[0]);
                }
                return default(V);
            }
        }
    }

    public sealed class Expression<T>
    {
        private readonly string _name;

        internal string Name { get { return _name; } }

        private static readonly Dictionary<string, Expression<T>> _expressions;

        static Expression()
        {
            _expressions = new Dictionary<string, Expression<T>>();
        }

        private Expression(string name)
        {
            _name = name;
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="System.String"/> to <see cref="Expressions.Compiler.Nonterminal"/>.
        /// </summary>
        /// <param name="name">The input name</param>
        /// <returns>The result of the conversion.</returns>
        public static implicit operator Expression<T>(string name)
        {
            return GetExpressions(name);
        }

        private static Expression<T> GetExpressions(string name)
        {
            if (!_expressions.ContainsKey(name))
            {
                _expressions.Add(name, new Expression<T>(name));
            }
            return _expressions[name];
        }

        private Func<T, IExpressionTree, T> _method;

        public Func<T, IExpressionTree, T> Eval
        {
            set
            {
                _method = value;
            }
        }

        public T this[T value, IExpressionTree tree]
        {
            get
            {
                if (tree != null)
                {
                    return _method(value, tree[0]);
                }
                return value;
            }
        }

        public T this[IExpressionTree tree]
        {
            get
            {
                if (tree != null)
                {
                    return _method(default(T), tree[0]);
                }
                return default(T);
            }
        }
    }
}
